//
//  AirBSDSocket.h
//  AirCpp
//
//  Created by Penghao on 14-2-25.
//  Copyright (c) 2014年 PengHao. All rights reserved.
//

//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
#ifndef AirCpp_AirBSDSocket_h
#define AirCpp_AirBSDSocket_h
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <sys/un.h>
#include <sys/select.h>
#include <sys/wait.h>
#include <netdb.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include "../AirIOType.h"
#include "../../AirContainer/AirArray.h"
#include "../../AirString/AirString.h"
#include "../AirSocket.h"
namespace AirCpp {
    
#define MAXHOSTNAME 30 //定义域名长度
#define PORTNUM 50000 /* random port number, we need something */

    /**
     *	基于BSDSocket的socket类
     */
    template <class CallBack>
    class AirBSDSocket : public AirSocket<CallBack> {
    protected:
        AirUInt32 read_rs = 0;
        int status;
        int reseive_time_out = 0;
        fd_set fdconn;
        timeval *tm = NULL;
        int socketHandle;
        unsigned int max_num_in_queue;
        hostent *hp;
        AirString *hostName;
        int port;
        AirSize_t bufferSize;
        bool isreading;
    public:
        long timeout;
        sockaddr_in *target_addr;
        
        AirBSDSocket(CallBack *call_back){
            target_addr = (sockaddr_in *)malloc(sizeof(sockaddr_in));
            memset(target_addr, 0, sizeof(sockaddr_in));
            this->callback_target = NULL;
            socketHandle = -1;
            hostName = NULL;
            port = 0;
            bufferSize = 1024;
            this->callback_target = call_back;
            isreading = false;
            
            FD_ZERO(&fdconn);
            if (AirBSDSocket<CallBack>::timeout>0) {
                tm = (timeval *)malloc(sizeof(timeval));
                memset(tm, 0, sizeof(timeval));
                tm->tv_sec = AirBSDSocket<CallBack>::timeout;
                tm->tv_usec = 0;
            }
        }
        
        ~AirBSDSocket(){
            this->callback_target = NULL;
            if (hostName!=NULL) {
                release(hostName);
            }
            free(target_addr);
            close(socketHandle);
        }
        
        /**
         *	初始化
         *
         *	@return	创建成功返回0 创建失败返回-1
         */
        int init(int domainType, int dataType, int protocol){
            return init(domainType, dataType, protocol, 0);
        }
        
        /**
         *	初始化 方法和上面一样
         *	@param 	domainType 	为创建的套接字指定协议集。 例如：
         *	AF_INET 表示IPv4网络协议
         *	AF_INET6 表示IPv6
         *	AF_UNIX 表示本地套接字（使用一个文件）
         *	@param 	dataType 	type 如下：
         *	SOCK_STREAM （可靠的面向流服务或流套接字）
         *	SOCK_DGRAM （数据报文服务或者数据报文套接字）
         *	SOCK_SEQPACKET （可靠的连续数据包服务）
         *	SOCK_RAW (在网络层之上的原始协议)
         *	@param 	protocol 	protocol 指定实际使用的传输协议。 最常见的就是IPPROTO_TCP、IPPROTO_SCTP、IPPROTO_UDP、IPPROTO_DCCP。这些协议都在<netinet/in.h>中有详细说明。 如果该项为“0”的话，即根据选定的domain和type选择使用缺省协议。
         *	@param 	time_out 	超时时间 默认为0 则设置为系统自己的值
         *
         *	@return	创建成功返回0 创建失败返回-1
         */
        int init(int domainType, int dataType, int protocol, long time_out){
            
            if ((socketHandle = socket(domainType, dataType, 0)) < 0)   /* create socket */
                return(-1);
            
            FD_SET(socketHandle, &fdconn);
            timeout = time_out;
            struct sigaction action;
            action.sa_handler = handle_pipe;
            sigemptyset(&action.sa_mask);
            action.sa_flags = 0;
            sigaction(SIGPIPE, &action, NULL);
            return 0;
        }
        
        static void handle_pipe(int sig)
        {
            //不做任何处理即可
            perror("Some socket connection is timeout!\n");
            printf("getpid = %d\n", getpid());
        }
        
        
        /**
         *	关闭连接
         */
        void close_connect()
        
        {
            close(socketHandle);
        }
        
        /**
         *	获取网络的ip地址
         *
         *	@param 	_host 	网络名称、网址
         *
         *	@return	返回ip地址
         */
        AirString * get_ip(const AirString *_host)
        
        {
            struct hostent *host = gethostbyname(_host->c_str);
            if(!host){
                herror("resolv");
                return NULL;
            }
            struct in_addr **list = (struct in_addr **)host->h_addr_list;
            return new AirString(inet_ntoa(*list[0]));
        }
        
        /**
         *	获取网络的信息
         *
         *	@return	返回主机信息
         */
        hostent *get_host_info(){
            char   myname[MAXHOSTNAME+1];
            gethostname(myname, MAXHOSTNAME);               /* who are we? */
            return(gethostbyname(myname));                     /* get our address info */
        }
        
    };
    
    
}
#endif
